package com.zhengbing.tj.aspect;

import com.zhengbing.tj.annotation.AuditLogRecord;
import com.zhengbing.tj.entity.AuditLog;
import com.zhengbing.tj.service.AsyncAuditLogService;
import com.zhengbing.tj.common.AuditLogUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

/**
 * 基于注解的审计日志切面类
 * 用于处理带有@AuditLogRecord注解的方法
 *
 * @author zhengbing
 * @date 2024-08-22
 */
@Aspect
@Component
public class AnnotationAuditLogAspect {
    
    @Autowired
    private AsyncAuditLogService asyncAuditLogService;
    
    /**
     * 定义切点，拦截所有带有@AuditLogRecord注解的方法
     */
    @Pointcut("@annotation(com.zhengbing.tj.annotation.AuditLogRecord)")
    public void auditLogPointcut() {}
    
    /**
     * 环绕通知，处理审计日志
     */
    @Around("auditLogPointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        
        // 获取@AuditLogRecord注解
        AuditLogRecord auditLogAnnotation = method.getAnnotation(AuditLogRecord.class);
        if (auditLogAnnotation == null) {
            // 如果没有注解，直接执行原方法
            return joinPoint.proceed();
        }
        
        // 获取注解属性
        String entityType = auditLogAnnotation.entityType();
        String operationType = auditLogAnnotation.operationType();
        String description = auditLogAnnotation.description();
        int idParamIndex = auditLogAnnotation.idParamIndex();
        boolean recordDetails = auditLogAnnotation.recordDetails();
        
        // 保存前的实体数据
        Object beforeData = null;
        Serializable entityId = null;
        Object target = joinPoint.getTarget();
        Object[] args = joinPoint.getArgs();
        String methodName = method.getName();
        
        // 如果指定了ID参数索引，获取实体ID
        if (idParamIndex >= 0 && args != null && args.length > idParamIndex && args[idParamIndex] instanceof Serializable) {
            entityId = (Serializable) args[idParamIndex];
        }
        
        // 根据操作类型自动判断
        if ("auto".equals(operationType)) {
            if (methodName.startsWith("save") || methodName.startsWith("add") || methodName.startsWith("create")) {
                operationType = AuditLogUtil.OPERATION_TYPE_INSERT;
            } else if (methodName.startsWith("update")) {
                operationType = AuditLogUtil.OPERATION_TYPE_UPDATE;
                // 如果是更新操作，记录更新前的数据
                if (recordDetails && entityId != null) {
                    try {
                        Method getByIdMethod = target.getClass().getMethod("getById", Serializable.class);
                        beforeData = getByIdMethod.invoke(target, entityId);
                    } catch (Exception e) {
                        // 记录异常但不影响主业务流程
                        e.printStackTrace();
                    }
                }
            } else if (methodName.startsWith("delete") || methodName.startsWith("remove")) {
                operationType = AuditLogUtil.OPERATION_TYPE_DELETE;
                // 如果是删除操作，记录删除前的数据
                if (recordDetails && entityId != null) {
                    try {
                        Method getByIdMethod = target.getClass().getMethod("getById", Serializable.class);
                        beforeData = getByIdMethod.invoke(target, entityId);
                    } catch (Exception e) {
                        // 记录异常但不影响主业务流程
                        e.printStackTrace();
                    }
                }
            }
        }
        
        // 执行原方法
        Object result = joinPoint.proceed();
        
        // 如果方法执行成功，记录审计日志
        if (result instanceof Boolean && (Boolean) result) {
            try {
                // 如果没有指定实体ID，尝试从返回值或参数中获取
                if (entityId == null) {
                    if (args != null && args.length > 0) {
                        Object arg = args[0];
                        try {
                            Method getIdMethod = arg.getClass().getMethod("getId");
                            Object idObj = getIdMethod.invoke(arg);
                            if (idObj instanceof Serializable) {
                                entityId = (Serializable) idObj;
                            }
                        } catch (Exception e) {
                            // 忽略异常
                        }
                    }
                }
                
                // 创建审计日志
                        AuditLog auditLog = null;
                        if (recordDetails) {
                            // 记录变更详情
                            if (AuditLogUtil.OPERATION_TYPE_INSERT.equals(operationType) && args != null && args.length > 0) {
                                // 插入操作，afterData为参数中的实体
                                auditLog = AuditLogUtil.createAuditLog(entityType, Long.valueOf(entityId.toString()),
                                        operationType, null, args[0]);
                            } else if (AuditLogUtil.OPERATION_TYPE_UPDATE.equals(operationType) && args != null && args.length > 0) {
                                // 更新操作，afterData为参数中的实体
                                auditLog = AuditLogUtil.createAuditLog(entityType, Long.valueOf(entityId.toString()),
                                        operationType, beforeData, args[0]);
                            } else if (AuditLogUtil.OPERATION_TYPE_DELETE.equals(operationType)) {
                                // 删除操作，beforeData为删除前的实体
                                auditLog = AuditLogUtil.createAuditLog(entityType, Long.valueOf(entityId.toString()),
                                        operationType, beforeData, null);
                            }
                        } else {
                            // 不记录变更详情，只记录基本信息
                            Map<String, Object> basicInfo = new HashMap<>();
                            basicInfo.put("entityType", entityType);
                            if (entityId != null) {
                                basicInfo.put("entityId", entityId);
                            }
                            
                            auditLog = AuditLogUtil.createAuditLog(entityType, 
                                    entityId != null ? Long.valueOf(entityId.toString()) : null,
                                    operationType, basicInfo, null);
                        }
                        
                        // 如果设置了描述，添加到审计日志
                        if (auditLog != null && !description.isEmpty()) {
                            auditLog.setDescription(description);
                        }
                        
                        // 异步记录审计日志
                        if (auditLog != null) {
                            asyncAuditLogService.recordAuditLogAsync(auditLog);
                        }
            } catch (Exception e) {
                // 记录异常但不影响主业务流程
                e.printStackTrace();
            }
        }
        
        return result;
    }
}